<?php
namespace app\common\model;
use think\exception\HttpException;
class Crypt
{

    static public $key;


    /**
     * 加密
     * @param $data
     * @param $key
     * @param int $expire
     * @return bool|mixed
     * @throws \Exception
     */

    static public function encrypt($data,$key,$expire=0) {
        if(empty($data)){
            return false;
        }
        $expire = sprintf('%010d', $expire ? $expire + time():0);
        $data = base64_encode($expire.$data);
        $x    = 0;
        $len  = strlen($data);
        $l    = strlen($key);
        $char = $str    =   '';

        try{
        for ($i = 0; $i < $len; $i++) {
            if ($x == $l) $x = 0;
            $char .= substr($key, $x, 1);
            $x++;
        }

        for ($i = 0; $i < $len; $i++) {
            $d_ch=substr($data, $i, 1);
            $d_code=self::ch2c($d_ch);
            $k_ch=substr($char, $i, 1);
            $k_code=self::ch2c($k_ch);
            $sum_code=($d_code+$k_code)%65;
            $str .= self::c2ch($sum_code);
        }

        $base64_str=base64_encode($str);
        }catch(\Exception $e){
            throw new HttpException(200,'加密错误:'.$data);
        }
        return str_replace(array('+','/','='),array('-','_',''),$base64_str);
    }

    /**解密
     * @param $data
     * @param $key
     * @return bool|mixed|string
     * @throws \Exception
     */
    static public function decrypt($data,$key) {
        if(empty($data)){
            return false;
        }
        $data   = str_replace(array('-','_'),array('+','/'),$data);
        $mod4   = strlen($data) % 4;
        if ($mod4) {
            $data .= substr('====', $mod4);
        }
        $data   = base64_decode($data);
        if(empty($data)){
            return '';
        }
        $x      = 0;
        $len    = strlen($data);
        $l      = strlen($key);
        $char   = $str = '';

        try{
        for ($i = 0; $i < $len; $i++) {
            if ($x == $l) $x = 0;
            $char .= substr($key, $x, 1);
            $x++;
        }

        for ($i = 0; $i < $len; $i++) {
            $d_ch=substr($data, $i, 1);
            $d_code=self::ch2c($d_ch);
            $k_ch=substr($char, $i, 1);
            $k_code=self::ch2c($k_ch);
            if ($d_code<$k_code) {
                $str .= self::c2ch($d_code + 65 - $k_code);
            }else{
                $str .= self::c2ch($d_code - $k_code);
            }
        }
        $data   = base64_decode($str);
        $expire = substr($data,0,10);
        if($expire > 0 && $expire < time()) {
            return '';
        }
        $data   = substr($data,10);
        }catch(\Exception $e){
            throw new HttpException(200,'解密错误:'.$data);
        }
        return $data;
    }

    /**
     * 获取秘钥
     * @param $token
     * @return bool|string
     */
    static public function getKey($token=''){
        if(empty($token)){
            $key=config('default_key');
            self::$key=$key;
            return $key;
        }

        $redis=new Redis();
        $key=$redis->get('token:'.$token);
        if($key){
            self::$key=$key;
            return $key;
        }else{
            throw new HttpException(200,'token错误');
        }

    }

    /**
     * 设置秘钥
     * @param $token
     * @param $key
     */
    static public function setToken($token,$key){
        if(empty($token)||empty($key)){
            throw new HttpException(200,'token或key均不能为空');
        }
        $redis=new Redis();
        $redis->set('token:'.$token,$key,config('token_ttl'));
    }

    /**
     * 加密机密用字符转换
     * @param $ch
     * @return mixed
     * @throws \Exception
     */
    static private function ch2c($ch){
        $chars=array(
            '0'=>0,'1'=>1,'2'=>2,'3'=>3,'4'=>4,'5'=>5,'6'=>6,'7'=>7,'8'=>8,'9'=>9,'a'=>10,
            'b'=>11,'c'=>12,'d'=>13,'e'=>14,'f'=>15,'g'=>16,'h'=>17,'i'=>18,'j'=>19,'k'=>20,
            'l'=>21,'m'=>22,'n'=>23,'o'=>24,'p'=>25,'q'=>26,'r'=>27,'s'=>28,'t'=>29,'u'=>30,
            'v'=>31,'w'=>32,'x'=>33,'y'=>34,'z'=>35,'A'=>36,'B'=>37,'C'=>38,'D'=>39,'E'=>40,
            'F'=>41,'G'=>42,'H'=>43,'I'=>44,'J'=>45,'K'=>46,'L'=>47,'M'=>48,'N'=>49,'O'=>50,
            'P'=>51,'Q'=>52,'R'=>53,'S'=>54,'T'=>55,'U'=>56,'V'=>57,'W'=>58,'X'=>59,'Y'=>60,
            'Z'=>61,'+'=>62,'/'=>63,'='=>64);
        if(isset($chars[$ch])){
            return $chars[$ch];
        }else{
            throw new HttpException(200,'ch2c出错:'.$ch);
        }
    }


    /**
     * 加密码解密用字符转换
     * @param $code
     * @return mixed
     * @throws \Exception
     */
    static private function c2ch($code)
    {
        $codes = array(
            0 => '0', 1 => '1', 2 => '2', 3 => '3', 4 => '4', 5 => '5', 6 => '6', 7 => '7', 8 => '8', 9 => '9', 10 => 'a',
            11 => 'b', 12 => 'c', 13 => 'd', 14 => 'e', 15 => 'f', 16 => 'g', 17 => 'h', 18 => 'i', 19 => 'j', 20 => 'k',
            21 => 'l', 22 => 'm', 23 => 'n', 24 => 'o', 25 => 'p', 26 => 'q', 27 => 'r', 28 => 's', 29 => 't', 30 => 'u',
            31 => 'v', 32 => 'w', 33 => 'x', 34 => 'y', 35 => 'z', 36 => 'A', 37 => 'B', 38 => 'C', 39 => 'D', 40 => 'E',
            41 => 'F', 42 => 'G', 43 => 'H', 44 => 'I', 45 => 'J', 46 => 'K', 47 => 'L', 48 => 'M', 49 => 'N', 50 => 'O',
            51 => 'P', 52 => 'Q', 53 => 'R', 54 => 'S', 55 => 'T', 56 => 'U', 57 => 'V', 58 => 'W', 59 => 'X', 60 => 'Y',
            61 => 'Z', 62 => '+', 63 => '/', 64 => '=');
        if(isset($codes[$code])){
            return $codes[$code];
        }else{
            throw new HttpException(200,'c2ch出错:'.$code);
        }
    }



}